package org.sdnstproject.interlayer.OF10Protocal;

import java.util.Random;
import org.projectfloodlight.openflow.types.U32;
import org.projectfloodlight.openflow.types.U8;
import org.sdnstproject.interlayer.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

//010600b000000003000000000000000100000100fe000000000000c700000ffffffe26a92064cc4b7331000000000000000000000000000000000001000000010000000000000000000000000000000000017e829847a2eb73312d657468310000000000000000000000000000000000000000c000000000000000000000000000027a0360211da273312d657468320000000000000000000000000000000000000000c0000000000000000000000000

public class FuFeaturesReplyV10 {

	private static final Logger log = LoggerFactory.getLogger(FuFeaturesReplyV10.class);
    public byte version = 1;
    public byte type = 0x6;
    public short length = 176;//MINIMUM_LENGTH = 32;
    public long xid = 0x0L;//需要dummyswitch设置
    public long datapathId = (long) 1;//需要dummyswitch设置
    public long nBuffers = (long) 256;
    public short nTables = (short) 254;
    /*public enum OFCapabilities {
	public final static int FLOW_STATS_VAL = 0x1;
    public final static int TABLE_STATS_VAL = 0x2;
    public final static int PORT_STATS_VAL = 0x4;
    public final static int IP_REASM_VAL = 0x20;
    public final static int QUEUE_STATS_VAL = 0x40;
    public final static int GROUP_STATS_VAL = 0x8;
    public final static int PORT_BLOCKED_VAL = 0x100;
     * */
    //OFFeaturesReplyVer10(xid=4294967294, datapathId=00:00:00:00:00:00:00:01, nBuffers=256, nTables=254, capabilities=[FLOW_STATS, TABLE_STATS, PORT_STATS, QUEUE_STATS, ARP_MATCH_IP], actions=[OUTPUT, SET_VLAN_VID, SET_VLAN_PCP, STRIP_VLAN, SET_DL_SRC, SET_DL_DST, SET_NW_SRC, SET_NW_DST, SET_NW_TOS, SET_TP_SRC, SET_TP_DST, ENQUEUE], ports=[OFPortDescVer10(portNo=local, hwAddr=c2:21:c9:0f:9b:4b, name=s1, config=[PORT_DOWN], state=[LINK_DOWN, STP_LISTEN], curr=[], advertised=[], supported=[], peer=[]), OFPortDescVer10(portNo=1, hwAddr=ea:a7:28:62:27:fd, name=s1-eth1, config=[], state=[LINK_DOWN, STP_LISTEN], curr=[PF_10GB_FD, PF_COPPER], advertised=[], supported=[], peer=[]), OFPortDescVer10(portNo=2, hwAddr=fe:44:32:d0:e1:0b, name=s1-eth2, config=[], state=[STP_LISTEN], curr=[PF_10GB_FD, PF_COPPER], advertised=[], supported=[], peer=[])])
    public int capabilities = 0xc7;//FLOW_STATS
    public int actions = 0xfff;
    //3 ports data:
    public byte[] ports = Utils.hexStringToByteArray("fffe26a92064cc4b73310000000000000000000000000000000000010000000100000000000000000000000000000000"
    												+"00017e829847a2eb73312d657468310000000000000000000000000000000000000000c0000000000000000000000000"
    												+"00027a0360211da273312d657468320000000000000000000000000000000000000000c0000000000000000000000000");
    
    public FuFeaturesReplyV10() {
    	
    }
    
    public FuFeaturesReplyV10 setXid(long xid) {
		this.xid = xid;
		return this;
	}
    
    public FuFeaturesReplyV10 setField(String field, String value) {
		switch (field) {
		case "version":
			this.version = Byte.parseByte(value);
			break;
		case "type":
			this.type = Byte.parseByte(value);
			break;
		case "length":
			this.length = Short.parseShort(value);
			break;
		case "xid":
			this.xid = Long.parseLong(value);
			break;
		case "datapathId":
			this.datapathId = Long.parseLong(value);
			break;
		case "nBuffers":
			this.nBuffers = Long.parseLong(value);
			break;
		case "nTables":
			this.nTables = Short.parseShort(value);
			break;
		case "capabilities":
			this.capabilities = Integer.parseInt(value);
			break;
		case "actions":
			this.actions = Integer.parseInt(value);
			break;
		case "ports":
			this.ports = new byte[48];
			new Random().nextBytes(ports);
			break;
		}
		return this;
	}
    
    public ByteBuf writeTo() {
    	ByteBuf bb = Unpooled.directBuffer();
    	int startIndex = bb.writerIndex();
        bb.writeByte(version);
        bb.writeByte(type);
        // length is length of variable message, will be updated at the end
        int lengthIndex = bb.writerIndex();
        bb.writeShort(length);

        bb.writeInt(U32.t(xid));
        bb.writeLong(datapathId);
        bb.writeInt(U32.t(nBuffers));
        bb.writeByte(U8.t(nTables));
        // pad: 3 bytes
        bb.writeZero(3);
        bb.writeInt(capabilities);
        bb.writeInt(actions);
        bb.writeBytes(ports);
        // update length field
        length = (short)(bb.writerIndex() - startIndex);
        bb.setShort(lengthIndex, length);
        return bb;
    }
    
    @Override
    public String toString() {
        StringBuilder b = new StringBuilder("OFFeaturesReplyVer10(");
        b.append("version=").append(version);
        b.append(", ");
        b.append("type=").append(type);
        b.append(", ");
        b.append("length=").append(length);
        b.append(", ");
        b.append("xid=").append(xid);
        b.append(", ");
        b.append("datapathId=").append(datapathId);
        b.append(", ");
        b.append("nBuffers=").append(nBuffers);
        b.append(", ");
        b.append("nTables=").append(nTables);
        b.append(", ");
        b.append("capabilities=").append(capabilities);
        b.append(", ");
        b.append("actions=").append(actions);
        b.append(", ");
        b.append("ports=").append(ports);
        b.append(")");
        return b.toString();
    }
}
